home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / jcool01.zip / RATIONAL.C < prev    next >
C/C++ Source or Header  |  1992-08-11  |  13KB  |  353 lines

  1. //
  2. // Copyright (C) 1991 Texas Instruments Incorporated.
  3. //
  4. // Permission is granted to any individual or institution to use, copy, modify,
  5. // and distribute this software, provided that this complete copyright and
  6. // permission notice is maintained, intact, in all copies and supporting
  7. // documentation.
  8. //
  9. // Texas Instruments Incorporated provides this software "as is" without
  10. // express or implied warranty.
  11. //
  12. //
  13. // Created: MBN 10/31/89 -- Initial design and implementation
  14. // Updated: MBN 03/04/90 -- Added execption for DIVIDE_BY_ZERO
  15. // Updated: MJF 03/12/90 -- Added group names to RAISE
  16. // Updated: MJF 07/31/90 -- Added terse print
  17. // Updated: DLS 04/01/91 -- New lite version
  18. // Updated: JAM 08/11/92 -- anach. form() replaced
  19. //
  20. // The CoolRational class  implements rational numbers  and arithmetic.  A CoolRational
  21. // object has the same precision and range of values as the built-in type long.
  22. // Implicit conversion to the system defined types short, int, long, float, and
  23. // double is supported by  overloaded  operator member functions.  Although the
  24. // CoolRational class makes judicous use  of inline  functions and  deals only with
  25. // integral values, the user  is warned that  the CoolRational  integer  arithmetic
  26. // class is still considerably slower than the built-in  integer data types. If
  27. // the range  of values  anticipated will  fit into a  built-in  type, use that
  28. // instead.
  29. //
  30.  
  31. #ifndef RATIONAL_H                // If no CoolRational class
  32. #include <cool/Rational.h>            // Include class definition
  33. #endif
  34.  
  35. #if defined(DOS)
  36. extern "C" {
  37. #include <stdlib.h>                // For exit()
  38. }
  39. #else
  40. #include <stdlib.h>                // For exit()
  41. #endif
  42. #include <stdio.h>                // For printf()
  43.  
  44.  
  45. // normalize -- Private function to normalize the numerator and denominator of
  46. //              a rational number
  47. // Input:       None
  48. // Output:      None
  49.  
  50. void CoolRational::normalize () {
  51.   if (this->num != 1 && this->den != 1) {    // Is there something to do?
  52.     long common = this->gcd (this->num, this->den); // Calculate GCD
  53.     if (common != 1) {                // If GCD is not one
  54.       this->num /= common;            // Calculate new numerator
  55.       this->den /= common;            // Calculate new denominator
  56.     }
  57.   }
  58.   if (this->den < 0) {                // If sign is in denominator
  59.     this->num *= -1;                // Multiply num and den by -1
  60.     this->den *= -1;                // To keep sign in numerator
  61.   }
  62.   this->state = N_OK;                // Set state to OK
  63. }
  64.  
  65.  
  66. // gcd -- calculate the GCD for two integer values
  67. // Input: Two long numbers
  68. // Output: Greatest common denominator
  69.  
  70. long CoolRational::gcd (long l1, long l2) {
  71.   long temp;
  72.   while (l2) {                    // While non-zero value
  73.     temp = l2;                    // Save current value
  74.     l2 = l1 % l2;                // Assign remainder of division
  75.     l1 = temp;                    // Copy old value
  76.   }
  77.   return l1;                    // Return GCD of numbers
  78. }
  79.  
  80.  
  81. // CoolRational -- Constructor with initial long arguments
  82. // Input:      Numerator, optional denominator
  83. // Output:     None
  84.  
  85. CoolRational::CoolRational (long n, long d) {
  86.   this->num = n;                // Set numerator
  87. #if ERROR_CHECKING                // If exception handling 
  88.   if (d == 0) {                    // Then if denominator is zero
  89.     //RAISE (Error, SYM(CoolRational), SYM(Zero_Denominator),
  90.     printf ("CoolRational::CoolRational(): Denominator of zero specified.\n");
  91.     abort ();                    // terminate in error with exit
  92.   }
  93. #endif
  94.   this->den = d;                // Set denominator
  95.   this->normalize ();                // Normalize rational
  96. }
  97.  
  98.  
  99. // operator short -- Impilict conversion operator from CoolRational to a short
  100. // Input:            None
  101. // Output:           Short value equivalent to truncated rational
  102.  
  103. CoolRational::operator short () {
  104.   long temp = this->truncate ();        // Return truncated rational
  105.   if (temp > MAXSHORT) {            // If too big for a short
  106.     this->state = N_OVERFLOW;            // Set condition state
  107.     this->overflow ("operator short()");    // Raise exception
  108.   }
  109.   if (temp < MINSHORT) {            // If too small for a short
  110.     this->state = N_UNDERFLOW;            // Set condition state
  111.     this->underflow ("operator short()");    // Raise exception
  112.   }
  113.   return (short)temp;                // Return converted value
  114. }
  115.  
  116.  
  117. // operator int -- Impilict conversion operator from CoolRational to an int
  118. // Input:          None
  119. // Output:         Int value equivalent to truncated rational
  120.  
  121. CoolRational::operator int () {
  122.   long temp = this->truncate ();        // Return truncated rational
  123.   if (temp > MAXINT) {                // If too big for an int
  124.     this->state = N_OVERFLOW;            // Set condition state
  125.     this->overflow ("operator int()");        // Raise exception
  126.   }
  127.   if (temp < MININT) {                // If too small for an int
  128.     this->state = N_UNDERFLOW;            // Set condition state
  129.     this->underflow ("operator int()");        // Raise exception
  130.   }
  131.   return (int)temp;                // Return converted value
  132. }
  133.  
  134.  
  135. // operator long -- Implicit conversion operator from CoolRational to a long
  136. // Input:           None
  137. // Output:          Long value equivalent to truncated rational
  138.  
  139. CoolRational::operator long () {
  140.   long temp = this->truncate ();        // Return truncated rational
  141.   if (temp > MAXLONG) {                // If too big for an int
  142.     this->state = N_OVERFLOW;            // Set condition state
  143.     this->overflow ("operator int()");        // Raise exception
  144.   }
  145.   if (temp < MINLONG) {                // If too small for an int
  146.     this->state = N_UNDERFLOW;            // Set condition state
  147.     this->underflow ("operator int()");        // Raise exception
  148.   }
  149.   return (long)temp;                // Return converted value
  150. }
  151.  
  152.  
  153. // operator float -- Implicit conversion operator from CoolRational to a float
  154. // Input:            None
  155. // Output:           Float value equivalent to rational
  156.  
  157. CoolRational::operator float ()
  158. {
  159.   if (this->num > MAXFLOAT || this->den > MAXFLOAT){// Out of range?
  160.     this->state = N_OVERFLOW;                // Set condition state
  161.     this->overflow ("operator float()");        // Raise exception
  162.   }
  163.   if ((this->num < 0.0 && (-this->num) < MINFLOAT) ||
  164.       (this->den < 0.0 && (-this->den) < MINFLOAT)){ // Out of ranbge?
  165.     this->state = N_UNDERFLOW;                // Set condition state
  166.     this->underflow ("operator float()");        // Raise exception
  167.   }
  168.   return ((float)this->num)/((float)this->den);        // Float answer
  169. }
  170.  
  171.  
  172. // invert -- Invert rational number
  173. // Input:    None
  174. // Output:   Reference to inverted number
  175.  
  176. CoolRational& CoolRational::invert () {
  177.   if (this->num == 0 && this->den != 0) {    // If zero numerator only
  178.     if (this->den < 0) {            // If negative denominator
  179.       this->state = N_MINUS_INFINITY;        // Set condition state
  180.       this->minus_infinity ("invert");        // And raise exception
  181.     }
  182.     else {
  183.       this->state = N_PLUS_INFINITY;        // Set condition state
  184.       this->plus_infinity ("invert");        // And raise exception
  185.     }
  186.   }
  187.   long temp = this->num;            // Save numerator
  188.   if (temp > 0) {
  189.     this->num = this->den;
  190.     this->den = temp;
  191.   } else {
  192.     this->num = this->den * -1;            // Switch denominator/numerator
  193.     this->den = temp * -1;            // And keep sign in numerator
  194.   }
  195.   return *this;                    // Return reference
  196. }
  197.  
  198.  
  199. // round -- Converts rational value by rounding to the nearest integer
  200. // Input:   None
  201. // Output:  Long
  202.  
  203. long CoolRational::round () const {
  204.   long ival = this->num / this->den;        // Calculate integer answer
  205.   if (ival > MAXDOUBLE)                // If too big
  206.     this->overflow ("operator double()");    // Raise exception
  207.   if (ival < 0 && (-ival) < MINDOUBLE)        // If out of range
  208.     this->underflow ("operator double()");    // Raise exception
  209.   double fval = ((double)this->num)/((double)this->den); // Double answer
  210.   if (ival < 0)                          // If negative
  211.     return (ival-(((-fval+ival) >= 0.5) ? 1 : 0));    // Round down if needed
  212.   else                              // Else positive, so
  213.     return (ival + (((fval - ival) >= 0.5) ? 1 : 0)); // Round up if needed
  214. }
  215.  
  216.  
  217. // operator+= -- Overload the addition with assignment operator for rational
  218. // Input:        Reference to a rational number
  219. // Output:       Mutated *this
  220.  
  221. CoolRational& CoolRational::operator+= (const CoolRational& r) {
  222.   if (this->den == r.den)            // If same denominator
  223.     this->num += r.num;                // Just add to numerator
  224.   else {
  225.     this->num = (this->num*r.den) + (this->den*r.num); // New numerator
  226.     this->den *= r.den;                       // New denominator
  227.   }
  228.   this->normalize ();                // Normalize rational
  229.   return *this;
  230. }
  231.  
  232.  
  233. // operator-= -- Overload the substraction with assignment operator for rational
  234. // Input:        Reference to a rational number
  235. // Output:       Mutated *this
  236.  
  237. CoolRational& CoolRational::operator-= (const CoolRational& r) {
  238.   if (this->den == r.den)            // If same denominator
  239.     this->num -= r.num;                // Just add to numerator
  240.   else {
  241.     this->num = (this->num*r.den) - (this->den*r.num); // New numerator
  242.     this->den *= r.den;                       // New denominator
  243.   }
  244.   this->normalize ();                // Normalize rational
  245.   return *this;
  246. }
  247.  
  248.  
  249. // operator*= -- Overload the multiply/assign operator for rational
  250. // Input:       Reference to a rational number
  251. // Output:      Reference to modified rational
  252.  
  253. CoolRational& CoolRational::operator*= (const CoolRational& r) {
  254.   this->num = this->num * r.num;        // Multiply numerators
  255.   this->den = this->den * r.den;        // Multiply denominators
  256.   this->normalize ();                // Normalize rational
  257.   return *this;                    // Return result
  258. }
  259.  
  260.  
  261. // operator/= -- Overload the divide with assignment operator for rational
  262. // Input:        Reference to a rational number
  263. // Output:       None
  264.  
  265. CoolRational& CoolRational::operator/= (const CoolRational& r) {
  266.   if (r.num == 0) {
  267.     this->state = N_DIVIDE_BY_ZERO;        // Set condition state
  268.     this->divide_by_zero ("operator/=()");
  269.   }
  270.   CoolRational temp(r);            // Create temporary work copy
  271.   return (*this *= temp.invert());
  272. }
  273.  
  274. // operator %= -- Overload the modulo with assignment operator for rational
  275. // Input:         Reference to a rational number
  276. // Output:        Mutated *this
  277.  
  278. CoolRational& CoolRational::operator%= (const CoolRational& r) {
  279.   if (this->den == r.den)            // If same denominator
  280.     this->num %= r.num;                // Just calculate modulus
  281.   else {
  282.     this->num = (this->num*r.den) % (this->den*r.num); // New numerator
  283.     this->den *= r.den;                       // New denominator
  284.   }
  285.   this->normalize ();                // Normalize rational
  286.   return *this;
  287. }
  288.  
  289. // minus_infinity -- Raise Error exception for negative infinity
  290. // Input:            Character string of derived class and function
  291. // Output:           None
  292.  
  293. void CoolRational::minus_infinity (const char* name) const {
  294.   //RAISE (Error, SYM(CoolRational), SYM(Minus_Infinity),
  295.   printf ("CoolRational::%s: Operation results in negative infinity value.\n",
  296.       name);
  297.   abort ();                    // terminate in error with exit
  298. }
  299.  
  300.  
  301. // plus_infinity -- Raise Error exception for positive infinity
  302. // Input:           Character string of derived class and function
  303. // Output:          None
  304.  
  305. void CoolRational::plus_infinity (const char* name) const {
  306.   //RAISE (Error, SYM(CoolRational), SYM(Plus_Infinity),
  307.   printf ("CoolRational::%s: Operation results in positive infinity value.\n",
  308.       name);
  309.   abort ();                    // terminate in error with exit
  310. }
  311.  
  312.  
  313. // overflow -- Raise Error exception for overflow occuring during conversion
  314. // Input:      Character string of derived class and function
  315. // Output:     None
  316.  
  317. void CoolRational::overflow (const char* name) const {
  318.   //RAISE (Error, SYM(CoolRational), SYM(Overflow),
  319.   printf ("CoolRational::%s: Overflow occured during type conversion.\n", name);
  320.   abort ();                    // terminate in error with exit
  321. }
  322.  
  323.  
  324. // underflow -- Raise Error exception for underflow occuring during conversion
  325. // Input:       Character string of derived class name and function
  326. // Output:      None
  327.  
  328. void CoolRational::underflow (const char* name) const {
  329.   //RAISE (Error, SYM(CoolRational), SYM(Underflow),
  330.   printf ("CoolRational::%s: Underflow occured during type conversion.\n", name);
  331.   abort ();                    // terminate in error with exit
  332. }
  333.  
  334.  
  335. // divide_by_zero -- Raise Error exception for divide by zero
  336. // Input:            Character string of derived class name and function
  337. // Output:           None
  338.  
  339. void CoolRational::divide_by_zero (const char* name) const {
  340.   //RAISE (Error, SYM(CoolRational), SYM(Divide_By_Zero),
  341.   printf ("CoolRational::%s: Divide by zero.\n", name);
  342.   abort ();                    // terminate in error with exit
  343. }
  344.  
  345.  
  346. // print --  terse print function for CoolRational
  347. // Inputs:   reference to output stream
  348. // Outputs:  none
  349.  
  350. void CoolRational::print(ostream& os) {
  351.   os << "                /* CoolRational " << (long)this << " */";
  352. }
  353.